package io.itit.ecp.admin.provide.action.controller.miniprogram;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.itit.ecp.admin.provide.action.resp.largescreen.CarbonReductionStatisticsResp;
import io.itit.ecp.admin.provide.action.resp.largescreen.ReductionCarbonSinkTrends;
import io.itit.ecp.admin.server.entity.CarbonSinkDataEntity;
import io.itit.ecp.admin.server.entity.CarbonSinkEntity;
import io.itit.ecp.admin.server.service.ICarbonSinkDataService;
import io.itit.ecp.admin.server.service.ICarbonSinkService;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 碳汇数据查询
 */
@Api(tags = "碳汇")
@RestController
@RequestMapping("/mini/carbonSinkFactor")
public class MiniCarbonSinkDataController {

    @Resource
    private ICarbonSinkService carbonSinkService;

    @Resource
    private ICarbonSinkDataService carbonSinkDataService;

    @ApiOperation("查询碳汇总量")
    @GetMapping("total")
    public ResultResp<Map<String, Object>> total(@RequestParam(required = false) String sceneProjectId,
                                                 @RequestParam(required = false) String sceneEdificeId,
                                                 @RequestParam(required = false) String sceneFloorId,
                                                 @RequestParam(required = false) String startTime,
                                                 @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        BigDecimal value = carbonSinkDataService.computeCarbonReductionTotal(sceneProjectId, sceneEdificeId, sceneFloorId, start, end);
        String unit = "kgce";
        BigDecimal t = new BigDecimal("1000");
        if (value.compareTo(t) >= 0) {
            unit = "tce";
            value = value.divide(t, 2, RoundingMode.HALF_DOWN);
        }
        Map<String, Object> result = new HashMap<>();
        result.put("value", value);
        result.put("unit", unit);
        return ResultResp.success(result);
    }


    /**
     * 碳汇趋势
     *
     * @param sceneProjectId sceneProjectId
     * @param sceneEdificeId sceneEdificeId
     * @param sceneFloorId   sceneFloorId
     * @param type           type 0：时；1：日
     * @param startTime      startTime
     * @param endTime        endTime
     */
    @ApiOperation("碳汇趋势")
    @GetMapping("carbonsinktrends")
    public ResultResp<ReductionCarbonSinkTrends> carbonSinkTrends(@RequestParam(required = false) String sceneProjectId,
                                                                  @RequestParam(required = false) String sceneEdificeId,
                                                                  @RequestParam(required = false) String sceneFloorId,
                                                                  @RequestParam String type,
                                                                  @RequestParam(required = false) String startTime,
                                                                  @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        String dateFormat = "yyyy-MM-dd HH:00";
        if (StringUtils.pathEquals("1", type)) {
            dateFormat = "yyyy-MM-dd";
        }
        String unit = "kgCO2";
        String finalFormat = dateFormat;
        List<CarbonSinkDataEntity> carbonSinkDataEntities = carbonSinkDataService.list(new LambdaQueryWrapper<CarbonSinkDataEntity>()
                .eq(StringUtils.hasLength(sceneProjectId), CarbonSinkDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), CarbonSinkDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), CarbonSinkDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(start), CarbonSinkDataEntity::getSolidifyDate, start)
                .le(CarbonSinkDataEntity::getSolidifyDate, end)
                .orderByAsc(CarbonSinkDataEntity::getSolidifyDate));
        Map<String, List<CarbonSinkDataEntity>> groupBySolidifyDateMap2 = carbonSinkDataEntities.stream()
                .collect(Collectors.groupingBy(item -> DateUtil.format(item.getSolidifyDate(), finalFormat), TreeMap::new, Collectors.toList()));
        List<ReductionCarbonSinkTrends.DataDetail> dataDetailList = new ArrayList<>();

        for (Map.Entry<String, List<CarbonSinkDataEntity>> entry : groupBySolidifyDateMap2.entrySet()) {
            dataDetailList.add(new ReductionCarbonSinkTrends.DataDetail().setTime(entry.getKey()).setValue(entry.getValue()
                    .stream()
                    .map(CarbonSinkDataEntity::getCarbonEmission)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN)));
        }
        BigDecimal t = new BigDecimal("1000");
        if (dataDetailList.stream()
                .anyMatch(item -> item.getValue().compareTo(t) >= 0)) {
            unit = "tCO2";
            for (ReductionCarbonSinkTrends.DataDetail item : dataDetailList) {
                item.setValue(item.getValue().divide(t, 2, RoundingMode.HALF_UP));
            }
        }
        return ResultResp.success(new ReductionCarbonSinkTrends().setName("碳汇").setUnit(unit).setData(dataDetailList));
    }


    /**
     * 碳汇统计
     *
     * @param sceneProjectId sceneProjectId
     * @param sceneEdificeId sceneEdificeId
     * @param sceneFloorId   sceneFloorId
     * @param startTime      startTime
     * @param endTime        endTime
     */
    @ApiOperation("碳汇统计")
    @GetMapping("carbonsinkstatics")
    public ResultResp<List<CarbonReductionStatisticsResp>> carbonSinkStatics(@RequestParam(required = false) String sceneProjectId,
                                                                             @RequestParam(required = false) String sceneEdificeId,
                                                                             @RequestParam(required = false) String sceneFloorId,
                                                                             @RequestParam(required = false) String startTime,
                                                                             @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        String unit = "kgCO2";
        BigDecimal t = new BigDecimal("1000");
        List<CarbonReductionStatisticsResp> dataList = new ArrayList<>();
        List<CarbonSinkEntity> sinkEntities = carbonSinkService.lambdaQuery().list();
        Map<String, List<CarbonSinkEntity>> typeMap = sinkEntities.stream().collect(Collectors.groupingBy(CarbonSinkEntity::getType));
        List<CarbonSinkDataEntity> carbonSinkDataEntities = carbonSinkDataService.list(new LambdaQueryWrapper<CarbonSinkDataEntity>()
                .select(CarbonSinkDataEntity::getType, CarbonSinkDataEntity::getSolidifyDate, CarbonSinkDataEntity::getCarbonEmission)
                .isNotNull(CarbonSinkDataEntity::getType)
                .eq(StringUtils.hasLength(sceneProjectId), CarbonSinkDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), CarbonSinkDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), CarbonSinkDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(start), CarbonSinkDataEntity::getSolidifyDate, start)
                .le(CarbonSinkDataEntity::getSolidifyDate, end)
                .orderByAsc(CarbonSinkDataEntity::getSolidifyDate));
        TreeMap<String, List<CarbonSinkDataEntity>> dataMap = carbonSinkDataEntities.stream()
                .collect(Collectors.groupingBy(item -> DateUtil.format(item.getSolidifyDate(), "yyyy-MM-dd HH:00"), TreeMap::new, Collectors.toList()));
        for (Map.Entry<String, List<CarbonSinkEntity>> entry : typeMap.entrySet()) {
            List<CarbonReductionStatisticsResp.DataItem> items = new ArrayList<>();
            Set<String> sinkDataIds = entry.getValue().stream().map(CarbonSinkEntity::getId).collect(Collectors.toSet());
            for (Map.Entry<String, List<CarbonSinkDataEntity>> sinkDataEntry : dataMap.entrySet()) {
                String date = sinkDataEntry.getKey();
                BigDecimal value = sinkDataEntry.getValue().stream()
                        .filter(item -> sinkDataIds.contains(item.getType()))
                        .map(CarbonSinkDataEntity::getCarbonEmission)
                        .reduce(BigDecimal.ZERO, BigDecimal::add)
                        .setScale(2, RoundingMode.HALF_DOWN);
                items.add(new CarbonReductionStatisticsResp.DataItem()
                        .setTime(date)
                        .setValue(value));
            }
            dataList.add(new CarbonReductionStatisticsResp().setData(items).setUnit(unit).setName(entry.getKey()));
        }
        if (dataList.stream().anyMatch(item -> item.getData().stream().anyMatch(dataItem -> dataItem.getValue().compareTo(t) >= 0))) {
            unit = "tCO2";
            for (CarbonReductionStatisticsResp statisticsResp : dataList) {
                statisticsResp.setUnit(unit);
                for (CarbonReductionStatisticsResp.DataItem item : statisticsResp.getData()) {
                    item.setValue(item.getValue().divide(t, 2, RoundingMode.HALF_DOWN));
                }
            }
        }
        return ResultResp.success(dataList);
    }

}
